﻿namespace Mangosoft.DiceCopy.Infrastructure.Data.MainBoundedContext.UnitOfWork {
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using System.Data.Entity.ModelConfiguration.Conventions;
    using System.Linq;
    using Mangosoft.DiceCopy.Domain.MainBoundedContext.Aggregates.AdvertisingAgg;
    using Mangosoft.DiceCopy.Domain.MainBoundedContext.Aggregates.JobseekerAgg;
    using Mangosoft.DiceCopy.Domain.MainBoundedContext.Aggregates.NewsAgg;
    using Mangosoft.DiceCopy.Domain.MainBoundedContext.Aggregates.ResumeAgg;
    using Mangosoft.DiceCopy.Infrastructure.Data.MainBoundedContext.UnitOfWork.Mapping;
    using Mangosoft.DiceCopy.Infrastructure.Data.Seedwork;
    using Mangosoft.DiceCopy.Domain.MainBoundedContext.Aggregates.CoverLetterAgg;

    public class MainBCUnitOfWork
        : DbContext, IQueryableUnitOfWork {

        #region IDbSet Members

        IDbSet<Jobseeker> _jobseekers;
        public IDbSet<Jobseeker> Jobseekers {
            get {
                if (_jobseekers == null)
                    _jobseekers = base.Set<Jobseeker>();

                return _jobseekers;
            }
        }

        IDbSet<News> _news2;
        public IDbSet<News> News2 {
            get {
                if (_news2 == null)
                    _news2 = base.Set<News>();

                return _news2;
            }
        }

        IDbSet<Advertising> _ads;
        public IDbSet<Advertising> Ads {
            get {
                if (_ads == null)
                    _ads = base.Set<Advertising>();

                return _ads;
            }
        }

        IDbSet<Resume> _resumes;
        public IDbSet<Resume> Resumes {
            get {
                if (_resumes == null)
                    _resumes = base.Set<Resume>();

                return _resumes;
            }

        }



        IDbSet<CoverLetter> _coverLetters;
        public IDbSet<CoverLetter> CoverLetters {
            get {
                if (_coverLetters == null)
                    _coverLetters = base.Set<CoverLetter>();

                return _coverLetters;
            }
        }



        #endregion

        #region IQueryableUnitOfWork Members

        public DbSet<TEntity> CreateSet<TEntity>()
            where TEntity : class {
            return base.Set<TEntity>();
        }

        public void Attach<TEntity>(TEntity item)
            where TEntity : class {
            //attach and set as unchanged
            base.Entry<TEntity>(item).State = System.Data.EntityState.Unchanged;
        }

        public void SetModified<TEntity>(TEntity item)
            where TEntity : class {
            //this operation also attach item in object state manager
            base.Entry<TEntity>(item).State = System.Data.EntityState.Modified;
        }
        public void ApplyCurrentValues<TEntity>(TEntity original, TEntity current)
            where TEntity : class {
            //if it is not attached, attach original and set current values
            base.Entry<TEntity>(original).CurrentValues.SetValues(current);
        }

        public void Commit() {
            base.SaveChanges();
        }

        public void CommitAndRefreshChanges() {
            bool saveFailed = false;

            do {
                try {
                    base.SaveChanges();

                    saveFailed = false;

                }
                catch (DbUpdateConcurrencyException ex) {
                    saveFailed = true;

                    ex.Entries.ToList()
                              .ForEach(entry => {
                                  entry.OriginalValues.SetValues(entry.GetDatabaseValues());
                              });

                }
            } while (saveFailed);

        }

        public void RollbackChanges() {
            // set all entities in change tracker 
            // as 'unchanged state'
            base.ChangeTracker.Entries()
                              .ToList()
                              .ForEach(entry => entry.State = System.Data.EntityState.Unchanged);
        }

        public IEnumerable<TEntity> ExecuteQuery<TEntity>(string sqlQuery, params object[] parameters) {
            return base.Database.SqlQuery<TEntity>(sqlQuery, parameters);
        }

        public int ExecuteCommand(string sqlCommand, params object[] parameters) {
            return base.Database.ExecuteSqlCommand(sqlCommand, parameters);
        }

        #endregion

        #region DbContext Overrides

        protected override void OnModelCreating(DbModelBuilder modelBuilder) {
            //Remove unused conventions
            modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

            //Add entity configurations in a structured way using 'TypeConfiguration’ classes
            modelBuilder.Configurations.Add(new JobseekerEntityConfiguration());
            modelBuilder.Configurations.Add(new NewsEntityConfiguration());
            modelBuilder.Configurations.Add(new AdvertisingEntityConfiguration());
            modelBuilder.Configurations.Add(new ResumeEntityConfiguration());
            modelBuilder.Configurations.Add(new EducationEntityConfiguration());
            modelBuilder.Configurations.Add(new CoverLetterEntityConfiguration());

        }
        #endregion
    }
}
